package com.hh.game.service.gateway.manager;

import com.alibaba.fastjson.JSONObject;
import com.hh.game.common.base.exception.GameException;
import com.hh.game.service.gateway.manager.service.ServiceRouteConfigCache;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.utils.ReferenceConfigCache;
import org.apache.dubbo.rpc.service.GenericService;

public class RpcManager {

    public static Object invoke(RouteInfo route) {
        // 引用远程服务
        // 该实例很重量，里面封装了所有与注册中心及服务提供方连接，请缓存
        ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
        // 弱类型接口名
        reference.setInterface(route.getInterfaceName());
        reference.setVersion(route.getVersion());
        // 声明为泛化接口
        reference.setGeneric("true");

        // 用org.apache.dubbo.rpc.service.GenericService可以替代所有接口引用
//        GenericService genericService = reference.get();
        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
        GenericService genericService = cache.get(reference);

        String[] parameterTypes;
        Object[] args;
        if (route.isByte()) {
            parameterTypes = new String[]{"byte[]"};
            args = new Object[]{route.getBytes()};
        } else if (route.isString()) {
            parameterTypes = new String[]{"java.lang.String"};
            args = new Object[]{route.getStringData()};
        } else {
            //获取方法签名列表
            parameterTypes = ServiceRouteConfigCache.getParameterTypes(route.getServiceName(),
                    ServiceRouteConfigCache.buildMethodSign(route.getHandler(), route.getMethod()));
            if (parameterTypes == null) {
                throw new GameException(GameException.ILLEGAL_REQUEST, route.route(), "method signature not find");
            } else {
                args = new Object[parameterTypes.length];
                if (parameterTypes.length > 0) {
                    JSONObject arg = route.getData();

                    // 基本类型以及Date,List,Map等都需要使用方法参数名称取值
                    String[] argsName = ServiceRouteConfigCache.getArgsName(route.getServiceName(),
                            ServiceRouteConfigCache.buildMethodSign(route.getHandler(), route.getMethod()));
                    if (arg == null) {
                        for (int i = 0; i < parameterTypes.length; i++) {
                            args[i] = null;
                        }
                    } else if (argsName != null) {
                        for (int i = 0; i < parameterTypes.length; i++) {
                            args[i] = arg.get(argsName[i]);
                        }
                    } else {
                        for (int i = 0; i < parameterTypes.length; i++) {
                            args[i] = arg;
                        }
                    }
                }
            }
        }

        // 基本类型以及Date,List,Map等不需要转换，直接调用
        Object result = genericService.$invoke(route.getMethod(), parameterTypes, args);
        return result;
    }

}
